package com.bjut.vendormgrsys.support.filter.jwt;

import com.bjut.vendormgrsys.config.RsaKeyProperties;
import com.bjut.vendormgrsys.model.domain.TokenPO;
import com.bjut.vendormgrsys.service.UserService;
import com.bjut.vendormgrsys.support.bo.Payload;
import com.bjut.vendormgrsys.support.bo.UserBO;
import com.bjut.vendormgrsys.support.wrapper.RequestWrapper;
import com.bjut.vendormgrsys.util.JwtUtils;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;

@Slf4j
public class JwtVerifyFilter extends BasicAuthenticationFilter implements IJwtFilter {

    private final RsaKeyProperties rsaKeyProperties;
    private final UserService userService;

    public JwtVerifyFilter(AuthenticationManager authenticationManager, RsaKeyProperties rsaKeyProperties, UserService userService) {
        super(authenticationManager);
        this.rsaKeyProperties = rsaKeyProperties;
        this.userService = userService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String tokenId = request.getHeader("Authorization");
        String unAuthorization = request.getHeader("unAuthorization");
        UserBO userBO = null;
        if((unAuthorization != null && unAuthorization.equals("Y")) || request.getRequestURI().equals("/sysFile/fileShow") || request.getRequestURI().equals("/sysFile/download")){
            userBO = (UserBO) userService.loadUserByUsername("visitor");
        } else {
            //没有登录
            if (tokenId == null || tokenId.length() == 0) {
                response(response,
                        HttpServletResponse.SC_UNAUTHORIZED, "请登录！", null);
                return;
            }
            //根据token主键查询用户token令牌
            TokenPO tokenPO = userService.getTokenPOById(tokenId);
            if (tokenPO == null) {
                response(response, HttpServletResponse.SC_UNAUTHORIZED, "请登录！", null);
                return;
            }

            try {
                String token = tokenPO.getToken();
                // 从Token令牌中解析出当前用户信息
                Payload<UserBO> infoFromToken = JwtUtils.getInfoFromToken(token, rsaKeyProperties.getPublicKey(), UserBO.class);

                if (infoFromToken != null) {
                    userBO = infoFromToken.getUserInfo();
                }
                if(userBO != null && userBO.getAccount().equals("visitor")){ // 游客不可访问需要登录的接口
                    response(response,
                            HttpServletResponse.SC_UNAUTHORIZED, "请登录！", null);
                    return;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        try {
            if (userBO != null) {
                Authentication authResult = new UsernamePasswordAuthenticationToken
                        (userBO, userBO.getPassword(), userBO.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authResult);
                String method = request.getMethod();
                String contentType = request.getContentType();
                log.info("Request Method:\n{}", method + request.getRequestURI());
                if((contentType==null || !contentType.startsWith(MediaType.MULTIPART_FORM_DATA_VALUE)) && HttpMethod.POST.matches(method)){
                    RequestWrapper requestWrapper = new RequestWrapper(request);
                    try {
                        String requestBody = IOUtils.toString(requestWrapper.getInputStream(), StandardCharsets.UTF_8);
                        log.info("Request Body:\n{}", requestBody);
                    } catch (Exception e) {
                        log.warn("Log requestWrapper body failed:", e);
                    }
                    chain.doFilter(requestWrapper, response);
                } else {
                    chain.doFilter(request, response);
                }
            } else {
                userService.deleteTokenPOById(tokenId);
                response(response, HttpServletResponse.SC_UNAUTHORIZED, "请重新登录！", null);
            }
        } catch (ExpiredJwtException e) {
            userService.deleteTokenPOById(tokenId);
            response(response, HttpServletResponse.SC_UNAUTHORIZED, "请重新登录！", null);
        }
    }
}
